原題:
https://cses.fi/problemset/task/1671
題意:
給定一張有向圖(n 點、m 邊),邊權非負。從節點 1 出發,輸出到每個節點的最短距離。若不可達,距離會維持為很大的數(常設為 INF)並輸出。
解題思路:
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, m; 
    cin >> n >> m;
    const long long INF = (long long)4e18;
    vector<vector<pair<int,int>>> g(n+1);
    for(int i=0;i<m;i++){
        int a,b,w; cin>>a>>b>>w;
        g[a].push_back({b,w});
    }
    vector<long long> dist(n+1, INF);
    priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;
    dist[1]=0; pq.push({0,1});
    while(!pq.empty()){
        auto [d,u]=pq.top(); pq.pop();
        if(d!=dist[u]) continue; // 已有更短解
        for(auto [v,w]: g[u]){
            if(dist[v] > d + w){
                dist[v] = d + w;
                pq.push({dist[v], v});
            }
        }
    }
    for(int i=1;i<=n;i++){
        cout << dist[i] << (i==n?'\n':' ');
    }
    return 0;
}
原題:
https://cses.fi/problemset/task/1195
題意:
從節點 1 走到節點 n,你可以對 其中一條邊 使用折扣(價格 / 2,向下取整)。求最短距離。
解題思路:
#include <bits/stdc++.h>
using namespace std;
struct State{
    long long d; int u; int used; // used=0/1
    bool operator<(State const& o) const { return d > o.d; }
};
int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n, m; if(!(cin>>n>>m)) return 0;
    vector<vector<pair<int,int>>> g(n+1);
    for(int i=0;i<m;i++){
        int a,b,w; cin>>a>>b>>w;
        g[a].push_back({b,w});
    }
    const long long INF = (long long)4e18;
    vector<long long> d0(n+1, INF), d1(n+1, INF);
    priority_queue<State> pq;
    d0[1]=0; pq.push({0,1,0});
    while(!pq.empty()){
        auto [d,u,used]=pq.top(); pq.pop();
        if(used==0 && d!=d0[u]) continue;
        if(used==1 && d!=d1[u]) continue;
        for(auto [v,w]: g[u]){
            // 不用折扣
            if(used==0 && d0[v] > d + w){
                d0[v] = d + w;
                pq.push({d0[v], v, 0});
            }
            if(used==1 && d1[v] > d + w){
                d1[v] = d + w;
                pq.push({d1[v], v, 1});
            }
            // 這條邊使用折扣
            if(used==0){
                long long nd = d + (long long)w/2; // 向下取整
                if(d1[v] > nd){
                    d1[v] = nd;
                    pq.push({d1[v], v, 1});
                }
            }
        }
    }
    cout << d1[n] << "\n"; // 必須使用過一次折扣的最短距離
    return 0;
}
原題:
https://leetcode.com/problems/network-delay-time/description/
題意:
給定有向邊 times[i] = {u, v, w} 表示 u→v 需要時間 w,總共有 n 個節點,從起點 k 發送訊號。訊號到達所有節點需要的最久時間是多少?若有節點不可達回傳 -1。
解題思路:
class Solution {
public:
    int networkDelayTime(vector<vector<int>>& times, int n, int k) {
        const long long INF = (long long)4e18;
        vector<vector<pair<int,int>>> g(n+1);
        for(auto &e: times) g[e[0]].push_back({e[1], e[2]});
        vector<long long> dist(n+1, INF);
        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;
        dist[k]=0; pq.push({0,k});
        while(!pq.empty()){
            auto [d,u]=pq.top(); pq.pop();
            if(d!=dist[u]) continue;
            for(auto [v,w]: g[u]){
                if(dist[v] > d + w){
                    dist[v] = d + w;
                    pq.push({dist[v], v});
                }
            }
        }
        long long ans = 0;
        for(int i=1;i<=n;i++) ans = max(ans, dist[i]);
        return ans >= INF/2 ? -1 : (int)ans;
    }
};
原題:
https://leetcode.com/problems/path-with-minimum-effort/
題意:
給定高度矩陣 h,從 (0,0) 走到 (n-1,m-1)。一步的費用為相鄰格高度差的絕對值。路徑的成本定義為沿途所有步驟費用的最大值。求使該「最大值」最小的路徑成本。
解題思路:
class Solution {
public:
    int minimumEffortPath(vector<vector<int>>& h) {
        int n = h.size(), m = h[0].size();
        const int INF = 1e9;
        vector<vector<int>> dist(n, vector<int>(m, INF));
        using T = tuple<int,int,int>; // d,x,y
        priority_queue<T, vector<T>, greater<T>> pq;
        auto inside = [&](int x,int y){return x>=0&&x<n&&y>=0&&y<m;};
        int dx[4]={1,-1,0,0}, dy[4]={0,0,1,-1};
        dist[0][0]=0; pq.push({0,0,0});
        while(!pq.empty()){
            auto [d,x,y]=pq.top(); pq.pop();
            if(d!=dist[x][y]) continue;
            if(x==n-1 && y==m-1) return d; // 最早彈出即最優
            for(int k=0;k<4;k++){
                int nx=x+dx[k], ny=y+dy[k];
                if(!inside(nx,ny)) continue;
                int w = abs(h[nx][ny]-h[x][y]);
                int nd = max(d, w);
                if(dist[nx][ny] > nd){
                    dist[nx][ny] = nd;
                    pq.push({nd, nx, ny});
                }
            }
        }
        return dist[n-1][m-1];
    }
};